package com.zhou.common.lib.util;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * AES加密128位CBC模式工具
 **/
@Slf4j
public class AesUtil {


    public static String byteToBase64(byte[] raw) {
        return Base64Utils.encodeToString(raw);
    }

    public static byte[] base64ToByte(String base64Content) {
        return Base64Utils.decodeFromString(base64Content);
    }


    public static byte[] randomIv() {

        Cipher cipher = null;//"算法/模式/补码方式"
        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            log.error("randomIv error!", e);
        }
        SecureRandom randomSecureRandom = new SecureRandom();
        byte[] iv = new byte[cipher.getBlockSize()];
        randomSecureRandom.nextBytes(iv);
        return iv;
    }

    public static byte[] randomKey() {
        return randomIv();
    }


    public static String encrypt(byte[] iv, byte[] key, String content) {

        try {
            SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
            IvParameterSpec ips = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ips);
            byte[] plain = content.getBytes(StandardCharsets.UTF_8);
            byte[] encoded = cipher.doFinal(plain);
            return byteToBase64(encoded);
        } catch (Exception e) {
            log.error("encrypt error!", e);
            throw new RuntimeException(e);
        }
    }

    public static String decrypt(byte[] iv, byte[] key, String content) {

        try {
            SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec ips = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ips);
            byte[] encoded = base64ToByte(content);
            byte[] plain = cipher.doFinal(encoded);
            return new String(plain, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("decrypt error!", e);
            throw new RuntimeException(e);
        }
    }


    public static String decryptWithSeed(byte[] iv, byte[] seed, String content) {

        try {
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(seed);
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            keygen.init(128, secureRandom);
            SecretKey originalKey = keygen.generateKey();
            byte[] encodedKey = originalKey.getEncoded();
            SecretKeySpec skeySpec = new SecretKeySpec(encodedKey, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec ips = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ips);
            byte[] encoded = base64ToByte(content);
            byte[] plain = cipher.doFinal(encoded);
            return new String(plain, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("decrypt error!", e);
            throw new RuntimeException(e);
        }
    }


    public static void main(String[] args) {

        byte[] iv = randomIv();
        byte[] key = randomKey();
        String ivs = byteToBase64(iv);
        String keys = byteToBase64(key);
        System.out.println("random iv str=" + ivs);
        System.out.println("random key str=" + keys);

        String content = "hello";
        String encrys = encrypt(iv, key, content);
        String original = decrypt(base64ToByte(ivs), base64ToByte(keys), encrys);
        System.out.println(original);

        System.out.println(RandomStringUtils.randomAlphabetic(8));
    }


}
